<?php

namespace Lib\Util;

use Exception,
    Imagick;

error_reporting(E_ALL);
ini_set('display_errors', 'On');

require_once __DIR__ . "/../../Config/constants.php";

class Image {

    public $resizeFilter = Imagick::FILTER_LANCZOS;
    public $resizeBlur   = 1;

    private $defaultParams = array(
        'file'  => null,
        'w'     => null,
        'h'     => null,
        'scale' => 'fit',
        'crop-position' => 'center'
    );
    private $params = array();

    private $img;
    private $filename;
    private $extension;
    private $originalWidth  = 0;
    private $originalHeight = 0;
    private $ratio = 1;

    public function __construct($params = array()) {
        $this->params = array_merge($this->defaultParams, $params);
        $dontProcess  = (int)$this->get('dont_process');

        $file = $this->get('file');
        if (is_file($file)) {
            $this->filename  = basename($file);
            $this->extension = strtolower(substr($this->filename, strrpos($this->filename, ".")+1));

            if (! $dontProcess) {
                $this->process($file);
            } else {
                $this->img = file_get_contents($file);
            }
            $this->output();
        } else {
            throw new Exception('Image file not found: `' . $file . '`');
        }
    }

    public function process($file) {
        $this->img = $this->cacheRead();
        if (! $this->img) {
            $this->newImage($file);
            $this->resize();
            $this->cacheWrite();
        }
        
    }

    public function output() {
        header("Content-Type: image/{$this->extension}");
        header("Content-Disposition:inline;filename={$this->filename}");
        header("X-Original-Width: {$this->originalWidth}");
        header("X-Original-Height: {$this->originalHeight}");
        echo $this->img;
    }

    private function get($name, $default = null) {
        return isset($this->params[$name]) ? $this->params[$name] : $default;
    }

    private function cacheRead() {
        $key = $this->cacheKey();
        return Cache::read($key);
    }

    private function cacheWrite() {
        $key = $this->cacheKey();
        return Cache::write($key, $this->img);
    }

    private function cacheKey() {
        $name = preg_replace('/\.[a-z]+$/', '', $this->get('file', ''));

        $key = "images" . DS . $name;
        foreach ($this->params as $k=>$v) {
            if ($k != 'file')
                $key .= "_" . $this->get($k, 'null');
        };
        $key .= "." . $this->extension;

        return $key;
    }

    private function newImage($file) {
        $this->img = new Imagick(DIR_IMG . DS . $file);
        $this->originalWidth  = $this->img->getImageWidth();
        $this->originalHeight = $this->img->getImageHeight();
        $this->ratio          = $this->originalWidth / $this->originalHeight;
    }

    private function resize() {
        $w     = $this->get('w');
        $h     = $this->get('h');
        $scale = $this->get('scale');

        if (isset($w) || isset($h)) {
            $newWidth  = $this->originalWidth;
            $newHeight = $this->originalHeight;

            switch(strtolower($scale)) {
                case 'fill';
                    if ($w != $newWidth) {
                        $newWidth  = $w;
                        $newHeight = $w / $this->ratio;
                    }

                    if ($newHeight < $h) {
                        $newHeight = $h;
                        $newWidth  = $h * $this->ratio;
                    }

                    //die("$newWidth x $newHeight");

                    if ($newWidth!=$this->originalWidth || $newHeight!=$this->originalHeight) {
                        $this->img->resizeImage($newWidth, $newHeight, $this->resizeFilter, $this->resizeBlur);

                        $cropPosition = $this->get('crop-position');
                        switch(strtolower($cropPosition)) {
                            case 'top-left':
                                $x = 0;
                                $y = 0;
                                break;

                            case 'top-right':
                                $x = $newWidth - $w;
                                $y = 0;
                                break;

                            case 'bottom-left':
                                $x = 0;
                                $y = $newHeight - $h;
                                break;

                            case 'bottom-right':
                                $x = $newWidth - $w;
                                $y = $newHeight - $h;
                                break;

                            // center
                            default:
                                $x = ($newWidth  - $w) / 2;
                                $y = ($newHeight - $h) / 2;
                                break;
                        }

                        $this->img->cropImage($w, $h, $x, $y);
                    }

                    break;

                // default: fit
                default:
                    if (isset($w)) {
                        $newWidth  = $w;
                        $newHeight = $w / $this->ratio;
                    }

                    if (isset($h) && $h<$newHeight) {
                        $newHeight = $h;
                        $newWidth  = $h * $this->ratio;
                    }

                    if ($newWidth!=$this->originalWidth || $newHeight!=$this->originalHeight) {
                        $this->img->resizeImage($newWidth, $newHeight, $this->resizeFilter, $this->resizeBlur);
                    }
                    break;
            }
        }
    }

}


?>